package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.algo.cooperation.common.PagerEntity;
import com.alibaba.algo.cooperation.feign.service.EmployeeFeignService;
import com.alibaba.algo.cooperation.feign.vo.req.FeignSelectEmployeeListByNameOrCodeRequestVO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.pagehelper.PageInfo;
import com.iwhalecloud.citybrain.flow.platform.api.in.*;
import com.iwhalecloud.citybrain.flow.platform.api.in.TaskCandidateCheckVo;
import com.iwhalecloud.citybrain.flow.platform.api.out.FlowFieldLimitDTO;
import com.iwhalecloud.citybrain.flow.platform.api.out.MustExpressDTO;
import com.iwhalecloud.citybrain.flow.platform.api.out.NodeAuth;
import com.iwhalecloud.citybrain.flow.platform.api.out.ObjectMetaDto;
import com.iwhalecloud.citybrain.flow.platform.api.out.TaskCandidateResultDto;
import com.iwhalecloud.citybrain.flow.platform.api.out.TaskDTO;
import com.iwhalecloud.citybrain.flow.platform.api.out.TaskUrlDTO;
import com.iwhalecloud.citybrain.flow.platform.http.FlowClientHttpService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.FormFieldLimitEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceActionEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.TaskReadEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.threadlocal.CommonOperateLogHolder;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.threadlocal.SdkCallTag;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.*;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.BeanCopierUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.JsonUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ModelUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.CommentTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.exception.TaskRollbackException;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowApp;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.eventconfig.DeployedEventConfigDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormFieldLimitDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.NextNodeCandidateTaskDTO;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.NodeCandidateTaskDTO;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.HttpFlowRecordsQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.ProcessInstanceDetailBaseInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.ProcessInstanceQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.object.ProcessObjectMetaDTO;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.object.ProcessObjectMetaQueryDTO;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.object.ProcessObjectMetaQueryResultDTO;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.CandidateEntity;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.GroupInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.PositionInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserRelationShip;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.NodeCandidateUsersSetting;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.common.exception.BusiException;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.Asserts;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.FormService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLinkInfo;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable.IS_REQUIRED_COMMENT;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable.MANUAL_SELECT_NEXT_NODE;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable.MUST_EXPRESS;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable.REQUIRED_ROLLBACK_COMMENT;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable.CHECK_POINT;
import static com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode.*;

/**
 * @author lilh
 * @date 2020/10/29 17:26
 */
@Api
@Slf4j
@RestController
public class FlowPlatformClientController implements FlowClientHttpService {

    @Autowired
    private CommandHandleManager commandHandleManager;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private FlowFormRepository flowFormRepository;

    @Autowired
    private FlowEventConfigRepository flowEventConfigRepository;

    @Autowired
    private FlowFunctionConfigRepository flowFunctionConfigRepository;
    @Autowired
    protected RuntimeService runtimeService;

    @Autowired
    private FormService formService;

    @Autowired
    FlowTaskService flowTaskService;

    @Autowired
    private FlowMonitorRepository flowMonitorRepository;

    @Autowired
    private FlowAppRepository appRepository;

    @Autowired
    private FlowModelRepository modelRepository;

    @Autowired
    private FlowTaskTraceRepository taskTraceRepository;

    @Autowired
    private FlowReModelCustomConfigRepository flowReModelCustomConfigRepository;

    @Autowired
    private FlowProcessService processService;


    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HttpServletResponse httpServletResponse;

    @Autowired
    private TaskService taskService;
    @Autowired
    private FlowNodeReaderRepository flowNodeReaderRepository;
    @Autowired
    private EmployeeFeignService employeeFeignService;

    @Autowired
    private FlowTerminateProcessRepository flowTerminateProcessRepository;

    @Autowired
    private FlowCancelProcessRepository flowCancelProcessRepository;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RemindCheckService remindCheckService;

    @Autowired
    private FlowProcessInstanceTraceRepository flowProcessInstanceTraceRepository;

    @Autowired
    private FlowTaskFinishedNoticeRepository flowTaskFinishedNoticeRepository;

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    private FlowTaskInstApproverRepository flowTaskInstApproverRepository;

    @Autowired
    private FlowFormService flowFormService;

    @Autowired
    private FlowProcessInstanceHandleRelRepository handleRelRepository;

    @Autowired
    private FlowProcessService flowProcessService;

    @Autowired
    private ResolveCandidateService resolveCandidateService;

    /**
     * 用户群组服务
     */
    @Autowired
    private UserGroupService userGroupService;

    /**
     * 用户职位服务
     */
    @Autowired
    private UserPositionService userPositionService;

    @Autowired
    private UserOrgService userOrgService;

    /**
     * 用户关系服务
     */
    @Autowired
    private UserRelationShipService userRelationShipService;

    @Autowired
    private FlowReNodeAuthRepository flowReNodeAuthRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private FlowRollbackService flowRollbackService;

    @Autowired
    private ProcessInstanceHandleRelService handleRelService;

    @Autowired
    private FlowObjectMetaService flowObjectMetaService;

    @Autowired
    private FlowObjectProcessInstanceRepository flowObjectProcessInstanceRepository;

    @Autowired
    private TaskVariableRepository taskVariableRepository;

    @Autowired
    private NodeCandidateService nodeCandidateService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private SequentNodeCandidateConfigService sequentNodeCandidateConfigService;

    @Autowired
    private FlowTaskVariableService flowTaskVariableService;

    @Autowired
    private FlowTurnTaskService flowTurnTaskService;

    @Autowired
    private FlowSupplyNodeService flowSupplyNodeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private FlowExecutionQueryService flowExecutionQueryService;

    @Override
    public ResponseResult applyProcess(HttpApplyProcessDto applyProcessDto) {
        log.info("Apply Param:", JSONObject.toJSONString(applyProcessDto));
        ResponseResult responseResult = this.createProcessInstance(convertToCreateProcessInstanceDto(applyProcessDto));
        if (!responseResult.isSuccess()) {
            return responseResult;
        }
        HttpCommandResultDto createResult = (HttpCommandResultDto) responseResult.getDatas();
        Asserts.notNull(createResult.getProcessInstanceId(), "成功创建的流程实例id不能为空");
        applyProcessDto.setProcessInstanceId(createResult.getProcessInstanceId());

        responseResult = this.startProcessInstance(convertToStartProcessInstanceDto(applyProcessDto));
        //如果需要在后续节点指定阅办人,
        //createProcessInstance已有 ，这边不需要重复记录
//        genReaderInfo(applyProcessDto.getTaskReadDoDto(), createResult.getProcessInstanceId() ,applyProcessDto.getParticipantId());
        return responseResult;
    }

    @Override
    public ResponseResult processInstance(HttpCommandDto httpCommandDto) {
        log.info("Request:" + JSON.toJSONString(httpCommandDto, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue));
        ResponseResult result = processService.getProcessInstanceDiagramAndInfo(httpCommandDto.getProcessInstanceId());
        log.info("Response:" + JSON.toJSONString(result));
        return result;
    }

    @Override
    public ResponseResult getStartForm(String modelKey) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(modelKey).latestVersion().singleResult();
        if (processDefinition == null) {
            throw new IllegalArgumentException("流程定义不存在");
        }
        if (processDefinition.hasStartFormKey()) {
            ResponseResult result = ResponseResult.success(flowFormRepository.findDeployForm(formService.getStartFormKey(processDefinition.getId())));
            log.info("Result:" + JSON.toJSONString(result, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue));
            return result;
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult getStartFormWithData(String processInstanceId) {
        if (StringUtils.isNotBlank(processInstanceId)) {
            ResponseResult result = ResponseResult.success(flowFormRepository.findStartFormDetail(processInstanceId));
            log.info("Result:" + JSON.toJSONString(result, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue));
            return result;
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult getTaskForm(String taskId) {
        ResponseResult result = ResponseResult.success(flowFormRepository.findTaskFormDetail(taskId, false));
        log.info("Result:" + JSON.toJSONString(result, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue));
        return result;
    }

    @Override
    public ResponseResult getTaskFormDataByTaskId(String taskId) {
        return ResponseResult.success(flowFormRepository.findTaskFormDetail(taskId, true));
    }

    @Override
    public ResponseResult<TaskDTO> getCurrentTaskIdByProcessInstanceId(String processInstanceId) {
        ResponseResult result;
        try {
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
            if (taskList != null && taskList.size() > 0) {
                log.info("根据实例ID[" + processInstanceId + "]查询任务记录结果[" + taskList + "]");
                TaskDTO taskDTO = new TaskDTO();
                taskDTO.setTaskId(taskList.get(0).getId());
                taskDTO.setTaskCode(taskList.get(0).getTaskDefinitionKey());
                if(taskList.size()>1) {
                    taskDTO.setTasks(new ArrayList<>());
                    taskList.forEach(task -> {
                        TaskDTO seqTask = new TaskDTO();
                        seqTask.setTaskId(task.getId());
                        seqTask.setTaskCode(task.getTaskDefinitionKey());
                        taskDTO.getTasks().add(seqTask);
                    });
                }
                result = ResponseResult.success(taskDTO);
            }
            else {
                result = ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), "根据实例ID查询任务ID失败!");
            }
        } catch (Exception e) {
            result = ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), "根据实例ID查询任务ID失败.");
        }
        log.info("GetCurrentTaskIdByProcessInstanceId Result:" + JSON.toJSONString(result));

        return result;
    }

    @Override
    public ResponseResult createProcessInstance(HttpCreateProcessInstanceDto createProcessInstanceDto) {
        log.info("CreateProcessInstance Request:" + JSON.toJSONString(createProcessInstanceDto));
        HttpCommandResultDto createProcessInstanceResult = commandHandleManager.handle(createProcessInstanceDto);
        ResponseResult responseResult;
        if (StrUtil.isNotBlank(createProcessInstanceResult.getProcessInstanceId())) {
            responseResult = ResponseResult.success(createProcessInstanceResult);
        } else {
            responseResult = ResponseResult.fail(
                    ErrorCode.CREATE_PROCESS_INSTANCE_FAILED.errCode(),
                    createProcessInstanceResult.getDealMsg()
            );
        }

        log.info("CreateProcessInstance Result:" + JSON.toJSONString(responseResult));
        //生成阅办人信息
//        genReaderInfo(createProcessInstanceDto.getTaskReadDoDtoList(), createProcessInstanceResult.getProcessInstanceId(),createProcessInstanceDto.getParticipantId());
        return responseResult;
    }

    @Override
    public ResponseResult startProcessInstance(HttpStartProcessInstanceDto startProcessInstanceDto) {
        log.info("StartProcessInstance Req:" + JSON.toJSONString(startProcessInstanceDto));
        //指定后续节点阅办信息
        genReaderInfo(startProcessInstanceDto.getTaskReadDoDtoList(), startProcessInstanceDto.getProcessInstanceId(), startProcessInstanceDto.getParticipantId());
        HttpCommandResultDto startResult = commandHandleManager.handle(startProcessInstanceDto);
        ResponseResult responseResult;
        if (startResult.getDealFlag() != null && startResult.getDealFlag() == false) {
            responseResult = ResponseResult.fail(
                    ErrorCode.START_PROCESS_INSTANCE_FAILED.errCode(),
                    startResult.getDealMsg()
            );
        } else {
            responseResult = ResponseResult.success(startResult);
        }
        log.info("StartProcessInstance ReS:" + JSON.toJSONString(responseResult));
        return responseResult;
    }

    /**
     * 如果需要在后续节点指定阅办人
     */
    private void genReaderInfo(List<TaskReadDoDto> taskReadDoDtoList, String processInstanceId, String sendUserCode) {

        if (CollectionUtils.isNotEmpty(taskReadDoDtoList)) {
            for (TaskReadDoDto trd : taskReadDoDtoList) {
                if (Objects.nonNull(trd) && StringUtils.isNotEmpty(trd.getReaderCode())
                        && StringUtils.isNotEmpty(trd.getReaderType())
                        && StringUtils.isNotEmpty(trd.getNodeCode())) {
                    //流程申请完毕，生成阅办人信息
                    List<String> userIds = getUserIds(trd.getReaderType(), trd.getReaderCode());
                    if (CollectionUtils.isNotEmpty(userIds)) {
                        for (String userId : userIds) {
                            //如果已经有阅办了，就跳过
                            if (readDoExist(userId, processInstanceId, trd.getNodeCode())) {
                                continue;
                            }
                            FlowNodeReaderVo vo = new FlowNodeReaderVo();
                            vo.setHandlerId(userId);
                            vo.setProcessInstanceId(processInstanceId);
                            // 目标节点
                            vo.setNodeCode(trd.getNodeCode());
                            vo.setSendUserCode(sendUserCode);
                            vo.setShouldCompleteTime(trd.getShouldCompleteTime());
                            // 来源节点
                            vo.setFromNodeCode(trd.getFromNodeCode());
                            try {
                                flowNodeReaderRepository.insert(vo);
                            } catch (Exception ex) {
                                log.error("FlowNodeReaderVo insert fail :" + ex.getMessage());
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据不同的类型，code获得用户编码
     */
    private List<String> getUserIds(String readerType, String readerCode) {
        List<String> userIds = new ArrayList<>();
        if (Objects.equals("STA", readerType)) {
            userIds.add(readerCode);
        } else if (Objects.equals("ORG", readerType)) {
            List<UserInfo> userInfos = userOrgService.getUserListByOrgId(readerCode);
            userIds = userInfos.stream().map(o -> o.getUserCode()).collect(Collectors.toList());
        } else if (Objects.equals("ROL", readerType)) {
            List<UserInfo> userInfos = userRoleService.getUserListByRoleId(readerCode);
            userIds = userInfos.stream().map(o -> o.getUserCode()).collect(Collectors.toList());
        } else if (Objects.equals("GROUP", readerType)) {
            List<UserInfo> userInfos = userGroupService.getUserListByGroupId(readerCode, null);
            userIds = userInfos.stream().map(o -> o.getUserCode()).collect(Collectors.toList());
        } else if (Objects.equals("POSITION", readerType)) {
            List<UserInfo> userInfos = userPositionService.getUserListByPositionId(readerCode);
            userIds = userInfos.stream().map(o -> o.getUserCode()).collect(Collectors.toList());
        }
        return userIds;
    }

    /**
     * 判断阅办是否存在
     */
    private boolean readDoExist(String handlerId, String processInstanceId, String nodeCode) {
        Integer res = flowNodeReaderRepository.readDoExist(handlerId, processInstanceId, nodeCode);
        if (res > 0) {
            return true;
        }
        return false;
    }

    @Override
    public ResponseResult completeWorkItem(HttpCompleteWorkItemDto completeWorkItemDto) {
        //生成后续节点的阅办信息
        genReaderInfo(completeWorkItemDto.getTaskReadDoDtoList(), completeWorkItemDto.getProcessInstanceId(), completeWorkItemDto.getParticipantId());
        log.info("CompleteWorkItem Req:" + JSON.toJSONString(completeWorkItemDto));
        ResponseResult result = ResponseResult.success(commandHandleManager.handle(completeWorkItemDto));
        log.info("CompleteWorkItem Res:" + JSON.toJSONString(result));

        return result;
    }

    @Override
    public ResponseResult terminateProcessInstance(HttpTerminateProcessInstanceDto httpTerminateProcessInstanceDto) {
        log.info("TerminateProcessInstance Req:" + JSON.toJSONString(httpTerminateProcessInstanceDto));
        HttpCommandResultDto httpCommandResultDto = commandHandleManager.handle(httpTerminateProcessInstanceDto);
        if (Objects.nonNull(httpCommandResultDto)) {
            if (!httpCommandResultDto.getDealFlag()) {
                return ResponseResult.fail(ErrorCode.TASK_HANDLE_ERROR.errCode(), httpCommandResultDto.getDealMsg());
            }
        }
        flowTerminateProcessRepository.flowTerminateProcessSendMessage(httpTerminateProcessInstanceDto);
        return ResponseResult.success();
    }

    @Override
    public ResponseResult cancelProcessInstance(HttpCancelProcessInstanceDto httpCancelProcessInstanceDto) {
        log.info("cancelProcessInstance Req:" + JSON.toJSONString(httpCancelProcessInstanceDto));
        boolean flag = true;
        String errMsg = null;
        try {
            flag = flowProcessService.cancelProcessInstance(httpCancelProcessInstanceDto);
        } catch (Exception e) {
            log.error("cancelProcessInstance exception", e);
            flag = false;
            errMsg = e.getMessage();
        }
        if (flag) {
            flowCancelProcessRepository.flowCancelProcessSendMessage(httpCancelProcessInstanceDto);
            return ResponseResult.success("撤销成功");
        }
        return ResponseResult.fail(ErrorCode.CANCEL_PROCESS_FAILED.errCode(), errMsg);
    }


    @Override
    public ResponseResult dispatchWorkItem(HttpDispatchWorkItemDto dispatchWorkItemDto) {
        log.info("dispatchWorkItem Req:" + JSON.toJSONString(dispatchWorkItemDto));
        return flowTurnTaskService.turnTask(dispatchWorkItemDto);
    }

    @Override
    public ResponseResult dispatchWorkItemNonUserCheck(HttpDispatchWorkItemDto dispatchWorkItemDto) {
        log.info("dispatchWorkItemNonUserCheck Req:" + JSON.toJSONString(dispatchWorkItemDto));
        return flowTurnTaskService.turnTaskNonUserCheck(dispatchWorkItemDto);
    }

    @Override
    public ResponseResult listTask(HttpTaskListQueryDto taskListQueryDto) {
        log.info("ListTask Req:" + JSON.toJSONString(taskListQueryDto));
        ResponseResult result = ResponseResult.success(commandHandleManager.handle(taskListQueryDto));
        return result;
    }

    @Override
    public ResponseResult listMyApply(HttpMyApplyQueryDto myApplyQueryDto) {
        log.info("ListMyApply Req:" + JSON.toJSONString(myApplyQueryDto));
        ResponseResult result = ResponseResult.success(commandHandleManager.handle(myApplyQueryDto));
        log.info("ListMyApply Res:" + JSON.toJSONString(result));
        return result;
    }

    @Override
    public ResponseResult getFlowRecords(String processInstanceId) {
        try {
            SdkCallTag.setTag(true);
            log.info("GetFlowRecords ProcessInstanceId:" + processInstanceId);
            ResponseResult result = ResponseResult.success(flowMonitorRepository.listFlowRecords(processInstanceId));
            log.info("GetFlowRecords Res:" + JSON.toJSONString(result));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.success(new ArrayList<>());
        } finally {
            SdkCallTag.remove();
        }
    }

    @Override
    public ResponseResult getModels(String appCode) {
        log.info("GetModels Req:" + appCode);
        if (StrUtil.isBlank(appCode)) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), PARAMETER_ERROR.errMessage());
        }
        List<FlowApp> apps = appRepository.listByAppCode(appCode);
        if (CollectionUtil.isEmpty(apps) || Objects.isNull(apps.get(0))) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), PARAMETER_ERROR.errMessage());
        }
        FlowApp app = apps.get(0);
        ModelQueryVo query = new ModelQueryVo();
        query.setAppId(app.getId());
        ResponseResult result = ResponseResult.success(modelRepository.listModel(query));
        log.info("GetModels Res:" + JSON.toJSONString(result));
        return result;
    }

    @Override
    public ResponseResult getTaskFormWithData(String processInstanceId, String taskNodeCode) {
        log.info("GetTaskFormWithData Req,ProcessInstanceId:" + processInstanceId + " TaskNodeCode:" + taskNodeCode);
        if (StrUtil.isBlank(processInstanceId) || StrUtil.isBlank(taskNodeCode)) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), PARAMETER_ERROR.errMessage());
        }
        //1.查询实例下已完成的任务
        List<FlowTaskTraceVo> completedTasks = taskTraceRepository.listCompletedTaskTraces(processInstanceId, taskNodeCode);
        //2.过滤出符合条件的任务
        List<FlowTaskTraceVo> tasks = completedTasks.stream().filter(item -> Objects.nonNull(item.getFormKey())).collect(Collectors.toList());
        ResponseResult result = ResponseResult.success(flowFormRepository.findTaskFormDetail(tasks, true));
        log.info("GetTaskFormWithData Res:" + JSON.toJSONString(result));
        return result;
    }

    @Override
    public ResponseResult<HttpProcessGraphResponseDto> generateProcessDiagram(HttpGetProcessGraphDto processGraphDto) {
        if (StrUtil.isBlank(processGraphDto.getProcessInstanceId())) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), PARAMETER_ERROR.errMessage());
        }
        log.info("GenerateProcessDiagram Req:" + JSON.toJSONString(processGraphDto));
        ResponseResult result = ResponseResult.success(processService.generateProcessDiagram(processGraphDto.getProcessInstanceId()));
        log.info("GenerateProcessDiagram Res:" + JSON.toJSONString(result));
        return result;
    }

    @Override
    public ResponseResult<HttpProcessXmlResponseDto> generateProcessXml(HttpGetProcessXmlDto processXmlDto) {
        log.info("generateProcessXml Req:" + JSON.toJSONString(processXmlDto));
        if (StrUtil.isBlank(processXmlDto.getProcessInstanceId())) {
            return ResponseResult.fail(PARAMETER_ERROR.errCode(), PARAMETER_ERROR.errMessage());
        }
        ResponseResult result = ResponseResult.success(processService.generateProcessXml(processXmlDto.getProcessInstanceId()));
        log.info("generateProcessXml Res:" + JSON.toJSONString(result));
        return result;
    }


    public ResponseResult selectEmployeeList(EmployeeQueryDto vo) {
        FeignSelectEmployeeListByNameOrCodeRequestVO requestVO = new FeignSelectEmployeeListByNameOrCodeRequestVO();
        requestVO.setEmployeeCodeOrEmployeeName(vo.getEmployeeName());
        requestVO.setPageIndex(vo.getPageIndex());
        requestVO.setPageSize(vo.getPageSize());
        log.info("SelectEmployeeList Req:" + JSON.toJSONString(requestVO));
        PagerEntity pagerEntity = employeeFeignService.selectPageByNameOrCode(requestVO);
        if (pagerEntity != null) {
            List<?> dataList = pagerEntity.getDataList();
            if (dataList != null) {
                for (Object obj : dataList) {
                    if (obj instanceof HashMap) {
                        HashMap map = (HashMap) obj;
                        Object userId = map.get("userId");
                        map.put("userId", userId == null ? null : String.valueOf(userId));
                    }
                }
            }
        }
        ResponseResult<PagerEntity> result = ResponseResult.success(pagerEntity);
        log.info("SelectEmployeeList Res:" + JSON.toJSONString(result));
        return result;
    }

    private HttpCreateProcessInstanceDto convertToCreateProcessInstanceDto(HttpApplyProcessDto applyProcessDto) {
        HttpCreateProcessInstanceDto createProcessInstanceDto = new HttpCreateProcessInstanceDto();
        String commandCode = createProcessInstanceDto.getCommandCode();
        BeanCopierUtils.copyProperties(applyProcessDto, createProcessInstanceDto);
        createProcessInstanceDto.setCommandCode(commandCode);
        return createProcessInstanceDto;
    }

    private HttpStartProcessInstanceDto convertToStartProcessInstanceDto(HttpApplyProcessDto applyProcessDto) {
        HttpStartProcessInstanceDto startProcessInstanceDto = new HttpStartProcessInstanceDto();
        String commandCode = startProcessInstanceDto.getCommandCode();
        BeanCopierUtils.copyProperties(applyProcessDto, startProcessInstanceDto);
        startProcessInstanceDto.setCommandCode(commandCode);
        return startProcessInstanceDto;
    }

    @GetMapping("/api/v1.0/public/getProcessInstanceDiagramAndInfo")
    public ResponseResult getProcessInstanceDiagramAndInfo(@RequestParam("processInstanceId") String processInstanceId) {
        try {
            SdkCallTag.setTag(true);
            log.info("getProcessInstanceDiagramAndInfo,ProcessInstId:" + processInstanceId);
            Map<String, Object> dataMap = new HashMap<>(4);
            //流程执行信息
            ProcessInstanceDetailBaseInfoVo baseInfo = new ProcessInstanceDetailBaseInfoVo();
            FlowProcessInstanceTraceVo processInstanceTrace = flowProcessInstanceTraceRepository.getProcessInstanceTraceByProcessInstanceId(processInstanceId);
            baseInfo.setProcessInstanceId(processInstanceId);
            baseInfo.setModelName(processInstanceTrace.getModelName());
            baseInfo.setApplyTime(processInstanceTrace.getStartTime());
            baseInfo.setApplyUserName(processInstanceTrace.getStarterName());
            baseInfo.setApplyUserId(processInstanceTrace.getStarterId());
            baseInfo.setAppName(processInstanceTrace.getAppName());
            baseInfo.setBusiName(processInstanceTrace.getBusiName());
            baseInfo.setStatus(processInstanceTrace.getStatus());
            baseInfo.setLinkStatus(processInstanceTrace.getLinkStatus());
            baseInfo.setCanRemind(resolveRemindTag(processInstanceTrace));
            baseInfo.setCanRecall(!isDone(processInstanceTrace));
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstanceTrace.getProcessDefinitionId()).singleResult();
            //获取流程资源
            InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName() + ".json");
            ProcessModelVo processModel = ModelUtils.getInstance().streamToModel(inputStream);
            Map<String, String> overrideIdAndResourceIdMap = new HashMap<>(8);
            if (processModel != null) {
                overrideIdAndResourceIdMap = getOverrideIdAndResourceIdMap(processModel);
            }

            //当前任务
            List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
            Set<String> taskSet = new HashSet<>(tasks.size());
            for (Task task : tasks) {
                if (overrideIdAndResourceIdMap.containsKey(task.getTaskDefinitionKey())) {
                    taskSet.add(overrideIdAndResourceIdMap.get(task.getTaskDefinitionKey()));
                } else {
                    taskSet.add(task.getTaskDefinitionKey());
                }
            }
            dataMap.put("model", ModelUtils.getInstance().transformToViewModel(processModel));
            dataMap.put("process", baseInfo);
            dataMap.put("currentTaskList", taskSet);
            ResponseResult result = ResponseResult.success(dataMap);
            log.info("getProcessInstanceDiagramAndInfo Result:" + JSON.toJSONString(result));
            return result;
        } catch (Exception e) {
            ResponseResult result = ResponseResult.success(new ArrayList<>());
            logger.error("SelectTaskList Error:" + e.getLocalizedMessage());
            e.printStackTrace();
            return result;
        } finally {
            SdkCallTag.remove();
        }
    }


    private boolean resolveRemindTag(FlowProcessInstanceTraceVo processInstanceTrace) {
        return !isDone(processInstanceTrace) && !remindCheckService.hasRemindTag(processInstanceTrace.getProcessInstanceId());
    }

    private boolean isDone(FlowProcessInstanceTraceVo processInstanceTrace) {
        return Objects.equals(ProcessInstanceLinkStatusEnum.END.getCode(), processInstanceTrace.getLinkStatus());
    }

    private Map<String, String> getOverrideIdAndResourceIdMap(ProcessModelVo processModel) {
        Map<String, String> overrideIdAndResourceIdMap = new HashMap<>(8);
        List<Object> childShapes = processModel.getChildShapes();
        for (Object childShape : childShapes) {
            String childShapeJsonStr = JsonUtils.toJson(childShape);
            JsonNode jsonNode = JsonUtils.readTree(childShapeJsonStr);
            if (jsonNode != null) {
                String type = jsonNode.get("stencil").get("id").asText();
                if (!"SequenceFlow".equals(type)) {
                    JsonNode properties = jsonNode.get("properties");
                    if (com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils.isNotEmpty(properties.get("overrideid").asText())) {
                        overrideIdAndResourceIdMap.put(properties.get("overrideid").asText(), jsonNode.get("resourceId").asText());
                    }
                }
            }
        }
        return overrideIdAndResourceIdMap;
    }

    @GetMapping("/api/v1.0/public/drawInst")
    public void drawInst(@RequestParam("instanceId") String instanceId) {
        log.info("DrawInst,InstanceId:" + instanceId);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(instanceId).list();
        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public ResponseResult selectYuezhiTaskList(FlowTaskFinishedNoticeQueryDto flowTaskFinishedNoticeQueryDto) {
        log.info("SelectYuezhiTaskList Req:" + JSON.toJSONString(flowTaskFinishedNoticeQueryDto));
        FlowTaskFinishedNoticeQueryVo queryVo = new FlowTaskFinishedNoticeQueryVo();
        BeanUtils.copyProperties(flowTaskFinishedNoticeQueryDto, queryVo);
        PageInfo<FlowTaskTraceVo> pageInfo = flowTaskFinishedNoticeRepository.selectPageList(queryVo);
        ResponseResult result = ResponseResult.success(pageInfo);
        log.info("SelectYuezhiTaskList Res:" + JSON.toJSONString(result));
        return result;
    }

    public ResponseResult getTaskInst(String taskId, String userId) {
        log.info("GetTaskInst Req: taskId=" + taskId + ",userId=" + userId);
        FlowTaskTraceVo flowTaskTraceVo = flowTaskTraceRepository.getTaskTraceByTaskId(taskId);
        ResponseResult result = ResponseResult.success(flowTaskTraceVo);
        log.info("GetTaskInst Res:" + JSON.toJSONString(result));
        //标记为已读
        flowTaskInstApproverRepository.updateReadFlag(taskId, userId, TaskReadEnum.READ.getReadFlag());
        return result;
    }

    @Override
    public ResponseResult todoTaskupdateReadFlag(UpdateReadVo updateReadVo) {
        log.info("todoTaskupdateReadFlag Req:" + updateReadVo);

        if (Objects.isNull(updateReadVo.getTaskId()) || Objects.isNull(updateReadVo.getUserCode())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), PARAM_NOT_EXIST.errMessage());
        }
        flowTaskInstApproverRepository.todoTaskupdateReadFlag(updateReadVo.getTaskId(), updateReadVo.getUserCode(), TaskReadEnum.READ.getReadFlag());

        return ResponseResult.success();
    }

    @Override
    public ResponseResult<List<FlowFieldLimitDTO>> getFormFieldLimitList(FlowFieldLimitQueryVo flowFieldLimitQueryVo) {
        log.info("getFormFieldLimitList Req:" + flowFieldLimitQueryVo);

        List<FormFieldLimitDomain> formFieldLimitDomainList = null;
        try {
            formFieldLimitDomainList = flowFormService.listByProcessInstanceIdOrTaskId(flowFieldLimitQueryVo.getProcessInstanceId(), flowFieldLimitQueryVo.getTaskId());
        } catch (Exception e) {
            log.error("getFormFieldLimitList error:", e);
            return ResponseResult.fail(ErrorCode.FORM_FIELD_QUERY_ERROR.errCode(), e.getMessage());
        }
        List<FlowFieldLimitDTO> flowFieldLimitDTOList = formFieldLimitDomainList.stream().map(this::converToFlowFieldLimitDto).collect(Collectors.toList());
        log.info("getFormFieldLimitList Res:" + flowFieldLimitDTOList);
        return ResponseResult.success(flowFieldLimitDTOList);
    }

    private FlowFieldLimitDTO converToFlowFieldLimitDto(FormFieldLimitDomain formFieldLimitDomain) {
        FlowFieldLimitDTO flowFieldLimitDTO = null;
        if (Objects.nonNull(formFieldLimitDomain)) {
            flowFieldLimitDTO = new FlowFieldLimitDTO();
            BeanCopierUtils.copyProperties(formFieldLimitDomain, flowFieldLimitDTO);
            FormFieldLimitEnum[] fieldLimitEnums = FormFieldLimitEnum.values();
            for (FormFieldLimitEnum fieldLimitEnum : fieldLimitEnums) {
                String code = fieldLimitEnum.getCode();
                try {
                    Field field = FlowFieldLimitDTO.class.getDeclaredField(code);
                    if (Objects.nonNull(field)) {
                        field.setAccessible(true);
                        Class fieldType = field.getType();
                        if (Objects.equals(fieldType.getName(), Integer.class.getName())) {
                            Integer fieldLimit = formFieldLimitDomain.getFieldLimit();
                            int value = (fieldLimit >> fieldLimitEnum.getBit()) & 1;
                            field.set(flowFieldLimitDTO, value);
                        }
                    }
                } catch (NoSuchFieldException e) {
                    log.error("NoSuchFieldException:", e);
                    continue;
                } catch (IllegalAccessException e) {
                    log.error("IllegalAccessException:", e);
                    continue;
                }
            }
        }
        return flowFieldLimitDTO;
    }

    /**
     * 获取阅办信息列表(查询我的阅办)
     *
     * @param processInstanceHandleRelDto
     * @return
     */
    @Override
    public ResponseResult getReadDoList(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto) {
        log.info("调用getReadDoList方法,请求参数列表:" + JSON.toJSONString(processInstanceHandleRelDto));
        // 阅办人ID
        String readCopyTo = processInstanceHandleRelDto.getReadCopyTo();
        if (StringUtils.isBlank(readCopyTo)) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "readCopyTo不能为空");
        }
        ResponseResult responseResult = ResponseResult.success(commandHandleManager.handle(processInstanceHandleRelDto));
        return responseResult;
    }

    /**
     * 更新阅办状态
     *
     * @param processInstanceHandleRelDto
     * @return
     */
    @Override
    public ResponseResult updateReadDoStatus(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto) {
        log.info("updateReadDoStatus Request:" + JSON.toJSONString(processInstanceHandleRelDto));
        return handleRelService.updateReadDoStatus(processInstanceHandleRelDto);
    }

    @Override
    public ResponseResult<TaskUrlDTO> getTaskApproveUrl(TaskApproveUrlQueryVo taskApproveUrlQueryVo) {
        String url = flowTaskService.getTaskExternalFormUrl(taskApproveUrlQueryVo.getTaskId());
        TaskUrlDTO taskUrlDTO = new TaskUrlDTO();
        taskUrlDTO.setTaskUrl(url);
        return ResponseResult.success(taskUrlDTO);
    }

    @Override
    public ResponseResult rollbackToPreNode(HttpTaskRollbackDto taskRollbackDto) {
        log.info("rollbackToPreNode Request:" + JSON.toJSONString(taskRollbackDto));

        try {
            CommonOperateLogHolder.setFromSdk(true);
            flowRollbackService.rollbackToPreNode(taskRollbackDto);
        } catch (TaskRollbackException ex) {
            logger.error("task rollback rollbackToPreNode fail", ex);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(),
                    ErrorCode.TASK_ROLLBACK_FAILED.errMessage() + ": " + ex.getMessage());
        } catch (Exception e) {
            logger.error("flowTaskService.rollbackToPreNode error:", e);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(), ErrorCode.TASK_ROLLBACK_FAILED.errMessage());
        } finally {
            CommonOperateLogHolder.removeAll();
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult takeBack(HttpTaskTakeBackDto taskTakeBackDto) {
        log.info("takeBack Request:" + JSON.toJSONString(taskTakeBackDto));

        try {
            return flowTaskService.takeBack(taskTakeBackDto);
        } catch (Exception e) {
            logger.error("flowTaskService.takeBack error:", e);
            return ResponseResult.fail(ErrorCode.TASK_TAKEBACK_FAILED.errCode(), ErrorCode.TASK_TAKEBACK_FAILED.errMessage());
        }
    }

    /**
     * 根据任务ID获取下一节点处理人信息
     *
     * @param taskId
     * @return
     */
    @Override
    public ResponseResult getNextNodeHandlerTask(String taskId) {
        log.info("getNextNodeHandlerTask Request:" + JSON.toJSONString(taskId));

        List<FlowSpecifyTheNodeHandlerTaskQueryInfo> specifyTheNodeHandlerTaskDataList = flowTaskService.getSpecifyTheNodeHandlerTask(taskId);

        log.info("getNextNodeHandlerTask Response:" + JSON.toJSONString(specifyTheNodeHandlerTaskDataList));
        return ResponseResult.success(specifyTheNodeHandlerTaskDataList)
                .setTotalCount(specifyTheNodeHandlerTaskDataList.size())
                .setPageSize(specifyTheNodeHandlerTaskDataList.size());
    }

    @Override
    public ResponseResult getSequentNodeCandidateConfig(SequentNodeCandidateConfigRequestDto sequentNodeCandidateConfigRequestDto) {
        log.info("getSequentNodeCandidateConfig Request:" + JSON.toJSONString(sequentNodeCandidateConfigRequestDto));

        SequentNodeCandidateConfigQueryVo sequentNodeCandidateConfigQueryVo = new SequentNodeCandidateConfigQueryVo();
        sequentNodeCandidateConfigQueryVo.setTaskId(sequentNodeCandidateConfigRequestDto.getTaskId());
        sequentNodeCandidateConfigQueryVo.setOnlyFirstLevelNodes(sequentNodeCandidateConfigRequestDto.isOnlyFirstLevelNodes());
        sequentNodeCandidateConfigQueryVo.setVariables(sequentNodeCandidateConfigRequestDto.getVariables());
        List<FlowSpecifyTheNodeHandlerTaskQueryInfo> flowSpecifyTheNodeHandlerTaskQueryInfoList = sequentNodeCandidateConfigService.getSequentNodeCandidateConfig(sequentNodeCandidateConfigQueryVo);
        log.info("getSequentNodeCandidateConfig Response:" + JSON.toJSONString(flowSpecifyTheNodeHandlerTaskQueryInfoList));
        return ResponseResult.success(flowSpecifyTheNodeHandlerTaskQueryInfoList);
    }

    /**
     * 根据实例ID和节点编码获取节点候选人对象
     *
     * @param processInstanceId
     * @param nodeCode
     * @return
     */
    @Override
    public ResponseResult getNodeCandidateInfoList(String processInstanceId, String nodeCode) {
        log.info("getSequentNodeCandidateConfig Request: processInstanceId=" + processInstanceId + ",nodeCode=" + nodeCode);

        FlowSpecifyTheNodeHandlerTaskQueryInfo candidateInfo = null;
        try {
            candidateInfo = flowTaskService.getCurrentNodeCandidateInfo(processInstanceId, nodeCode);
        } catch (Exception e) {
            logger.error("getNodeCandidateInfoList error", e);
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), e.getMessage());
        }
        log.info("getSequentNodeCandidateConfig Response:" + JSONObject.toJSONString(candidateInfo));
        return ResponseResult.success(candidateInfo);
    }

    @Override
    public ResponseResult rollbackToFirstNode(HttpTaskRollbackDto taskRollbackDto) {
        log.info("rollbackToFirstNode Request:" + JSON.toJSONString(taskRollbackDto));
        try {
            CommonOperateLogHolder.setFromSdk(true);
            flowRollbackService.rollbackToFirstNode(taskRollbackDto);
        } catch (TaskRollbackException ex) {
            logger.error("task rollback rollbackToFirstNode fail", ex);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(),
                    ErrorCode.TASK_ROLLBACK_FAILED.errMessage() + ": " + ex.getMessage());
        } catch (Exception e) {
            logger.error("flowTaskService.rollbackToFirstNode error:", e);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(),
                    ErrorCode.TASK_ROLLBACK_FAILED.errMessage());
        } finally {
            CommonOperateLogHolder.removeAll();
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult rollbackToTargetNode(HttpTaskRollbackDto taskRollbackDto) {
        log.info("rollbackToTargetNode Request:" + JSON.toJSONString(taskRollbackDto));

        try {
            CommonOperateLogHolder.setFromSdk(true);
            flowRollbackService.rollbackToTargetNode(taskRollbackDto);
        } catch (TaskRollbackException ex) {
            logger.error("task rollback rollbackToTargetNode fail", ex);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(),
                    ErrorCode.TASK_ROLLBACK_FAILED.errMessage() + ": " + ex.getMessage());
        } catch (Exception e) {
            logger.error("flowTaskService.rollbackToTargetNode error:", e);
            return ResponseResult.fail(ErrorCode.TASK_ROLLBACK_FAILED.errCode(), ErrorCode.TASK_ROLLBACK_FAILED.errMessage());
        } finally {
            CommonOperateLogHolder.removeAll();
        }
        return ResponseResult.success();
    }

    /**
     * 添加自定义函数配置
     *
     * @param customFunctionConfigDto
     * @return
     */
    @Override
    public ResponseResult saveFunctionConfig(HttpFunctionConfigDto customFunctionConfigDto) {
        log.info("saveFunctionConfig Request:" + JSON.toJSONString(customFunctionConfigDto));

        String functionName = customFunctionConfigDto.getFunctionName();
        if (StringUtils.isBlank(functionName)) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "自定义函数名称不能为空");
        }
        flowFunctionConfigRepository.saveFunctionConfig(customFunctionConfigDto);
        return ResponseResult.success(null);
    }

    /**
     * 删除自定义函数配置
     *
     * @param ids
     * @return
     */
    @Override
    public ResponseResult deleteFunctionConfig(String ids){
        log.info("deleteFunctionConfig Request:" + JSON.toJSONString(ids));

        JSONObject params= JSON.parseObject(ids);
        JSONArray array=params.getJSONArray("ids");
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<array.size();i++){
            list.add(array.getInteger(i));
        }
        if(flowFunctionConfigRepository.deleteFunctionConfig(list)){
            return ResponseResult.success("删除自定义函数成功");
        }
        return ResponseResult.fail(100,"删除失败，请联系运维人员");
    }

    /**
     * 根据函数名称获取自定义函数配置列表
     *
     * @param customFunctionConfigDto
     * @return
     */
    @Override
    public ResponseResult getFunctionConfigByFunName(HttpFunctionConfigDto customFunctionConfigDto) {
        return ResponseResult.success(flowFunctionConfigRepository.getFunctionConfigByFunName(customFunctionConfigDto));
    }

    @Override
    public ResponseResult getUserGroupList() {
        List<GroupInfo> groupInfos = userGroupService.getUserGroupList();
        return ResponseResult.success(groupInfos);
    }

    @Override
    public ResponseResult getAllPositionList() {
        List<PositionInfo> positionInfos = userPositionService.getAllPositions();
        return ResponseResult.success(positionInfos);
    }

    @Override
    public ResponseResult getUserRelationShipList() {
        List<UserRelationShip> userRelationShips = userRelationShipService.getUserRelationShipList();
        return ResponseResult.success(userRelationShips);
    }

    @Override
    public ResponseResult<TaskCandidateResultDto> queryCandidateTask(TaskCandidateCheckVo taskCandidateCheckVo) {
        log.info("queryCandidateTask Request:" + JSON.toJSONString(taskCandidateCheckVo));

        if (StringUtils.isBlank(taskCandidateCheckVo.getTaskId())) {
            return ResponseResult.fail(ErrorCode.TASK_ID_IS_NULL.errCode(), ErrorCode.TASK_ID_IS_NULL.errMessage());
        }

        if (StringUtils.isNotBlank(taskCandidateCheckVo.getUserCode())) {
            User user = userRepository.getUserWithOrgByCodeFromUserCenter(taskCandidateCheckVo.getUserCode());
            if (Objects.isNull(user)) {
                return ResponseResult.fail(ErrorCode.USER_NOT_EXIST.errCode(), ErrorCode.USER_NOT_EXIST.errMessage());
            }
        }

        FlowTaskTraceVo flowTaskTraceVo = flowTaskService.getFlowTaskByTaskIdOrUserCode(taskCandidateCheckVo.getTaskId(), taskCandidateCheckVo.getUserCode());
        TaskCandidateResultDto taskCandidateResultDto = new TaskCandidateResultDto();

        if (Objects.nonNull(flowTaskTraceVo)) {
            taskCandidateResultDto.setTaskId(flowTaskTraceVo.getTaskId());
            taskCandidateResultDto.setTaskStatus(flowTaskTraceVo.getLinkStatus());
            taskCandidateResultDto.setStatus(flowTaskTraceVo.getStatus());
            taskCandidateResultDto.setNodeCode(flowTaskTraceVo.getActivityId());
            taskCandidateResultDto.setNodeName(flowTaskTraceVo.getTaskName());
            FlowProcessInstanceTraceVo flowProcessInstanceTraceVo = flowProcessInstanceTraceRepository.getProcessInstanceTraceByProcessInstanceId(flowTaskTraceVo.getProcessInstanceId());
            List<FlowReNodeAuthVo> flowReNodeAuthVoList = flowReNodeAuthRepository.listNodeAuthByProcdefIdAndNodeCode(flowProcessInstanceTraceVo.getProcessDefinitionId(), flowTaskTraceVo.getActivityId());
            if (Objects.nonNull(flowReNodeAuthVoList) && !flowReNodeAuthVoList.isEmpty()) {
                NodeAuth nodeAuth = new NodeAuth();
                for (FlowReNodeAuthVo flowReNodeAuthVo : flowReNodeAuthVoList) {
                    try {
                        Field field = nodeAuth.getClass().getDeclaredField(flowReNodeAuthVo.getAuthName());
                        field.setAccessible(true);
                        field.set(nodeAuth, flowReNodeAuthVo.getAuthSwitch());
                    } catch (NoSuchFieldException e) {
                        log.error("get field error,continue");
                    } catch (IllegalAccessException e) {
                        log.error("set field value error,continue");
                    }
                }
                taskCandidateResultDto.setNodeAuth(nodeAuth);
            }
            //获取节点意见
            //1，获得部署id ,节点编码
            String processDefinitionId = flowProcessInstanceTraceVo.getProcessDefinitionId();
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
            String depId = processDefinition.getDeploymentId();
            String nodeCode = flowTaskTraceVo.getActivityId();
            //2，flow_re_model_custom_config 查询节点意见
            List<ModelCustomConfig> modelCustomConfigs = flowReModelCustomConfigRepository.listModelCustomConfig(depId, nodeCode, null);
            //需要返回的意见
            if (modelCustomConfigs != null && modelCustomConfigs.size() > 0) {
                for (ModelCustomConfig co : modelCustomConfigs) {
                    if (Objects.equals(co.getType(), IS_REQUIRED_COMMENT) && Objects.equals(co.getConfig(), "1")) {
                        taskCandidateResultDto.setRequiredComment(true);
                    } else if (Objects.equals(co.getType(), REQUIRED_ROLLBACK_COMMENT) && Objects.equals(co.getConfig(), "1")) {
                        taskCandidateResultDto.setRequiredRollbackComment(true);
                    } else if (Objects.equals(co.getType(), MUST_EXPRESS) && Objects.equals(co.getConfig(), "1")) {
                        taskCandidateResultDto.setMustExpress(true);
                    } else if (Objects.equals(co.getType(), MANUAL_SELECT_NEXT_NODE) && Objects.equals(co.getConfig(), "1")) {
                        taskCandidateResultDto.setManualSelectNextNode(true);
                    } else if (Objects.equals(co.getType(), CHECK_POINT) && Objects.equals(co.getConfig(), "1")) {
                        taskCandidateResultDto.setConfigCheckPoint(true);
                    }
                }
            }

            //解析处理人
            resolveTaskHandler(flowTaskTraceVo, taskCandidateResultDto);

            log.info("queryCandidateTask Response:" + JSON.toJSONString(taskCandidateResultDto));

            return ResponseResult.success(taskCandidateResultDto);
        } else {
            return ResponseResult.success();
        }
    }

    private void resolveTaskHandler(FlowTaskTraceVo flowTaskTraceVo, TaskCandidateResultDto taskCandidateResultDto) {
        List<TaskCandidateResultDto.HandlerEntity> list = new ArrayList<>();
        if (StringUtils.isNotBlank(flowTaskTraceVo.getOperatorCode())) {
            TaskCandidateResultDto.HandlerEntity handlerEntity = new TaskCandidateResultDto.HandlerEntity();
            handlerEntity.setCode(flowTaskTraceVo.getOperatorCode());
            handlerEntity.setType("STA");

            //如果已经有值，减少一次查询
            if (StringUtils.isNotBlank(flowTaskTraceVo.getOperator())) {
                handlerEntity.setName(flowTaskTraceVo.getOperator());
            } else {
                CandidateEntity candidateEntity = resolveCandidateService.getCandidateEntity("STA", flowTaskTraceVo.getOperatorCode());
                BeanCopierUtils.copyProperties(candidateEntity, handlerEntity);
            }
            list.add(handlerEntity);
        } else {

            Task task = taskService.createTaskQuery().taskId(flowTaskTraceVo.getTaskId()).singleResult();
            if (Objects.nonNull(task)) {
                task = taskService.createTaskQuery().taskId(flowTaskTraceVo.getTaskId()).includeIdentityLinks().singleResult();
                List<? extends IdentityLinkInfo> identityLinkEntityList = task.getIdentityLinks();
                if (CollectionUtils.isNotEmpty(identityLinkEntityList)) {
                    for (IdentityLinkInfo identityLinkInfo : identityLinkEntityList) {
                        TaskCandidateResultDto.HandlerEntity handlerEntity = new TaskCandidateResultDto.HandlerEntity();
                        String code = "";
                        if (StringUtils.isNotBlank(identityLinkInfo.getUserId())) {
                            code = identityLinkInfo.getUserId();
                        } else if (StringUtils.isNotBlank(identityLinkInfo.getGroupId())) {
                            code = identityLinkInfo.getGroupId();
                        }
                        CandidateEntity candidateEntity = resolveCandidateService.getCandidateEntity(identityLinkInfo.getType(), code);
                        BeanCopierUtils.copyProperties(candidateEntity, handlerEntity);
                        list.add(handlerEntity);
                    }
                }
            }
        }
        taskCandidateResultDto.setNodeHandler(list);
    }


    @Override
    public ResponseResult dealReadDoData(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto) {
        log.info("updateReadDoStatus Request:" + JSON.toJSONString(processInstanceHandleRelDto));
        return handleRelService.dealReadDoData(processInstanceHandleRelDto);
    }

    /**
     * 委派或指派任务
     *
     * @param httpDelegateTaskDto
     * @return
     */
    @Override
    public ResponseResult delegateTask(HttpDelegateTaskDto httpDelegateTaskDto) {
        log.info("httpDelegateTaskDto Request:" + JSON.toJSONString(httpDelegateTaskDto));
        return flowTaskService.delegateTaskByHttpRequest(httpDelegateTaskDto);
    }

    /**
     * 任务加签或多级加签
     *
     * @param httpAddSignTaskDto
     * @return
     */
    @Override
    public ResponseResult addSignTask(HttpAddSignTaskDto httpAddSignTaskDto) {
        log.info("httpDelegateTaskDto Request:" + JSON.toJSONString(httpAddSignTaskDto));
        return flowTaskService.addSignTaskByHttpRequest(httpAddSignTaskDto);
    }

    /**
     * 任务减签
     *
     * @param httpDeleteSignTaskDto
     * @return
     */
    @Override
    public ResponseResult deleteSignTask(@RequestBody HttpDeleteSignTaskDto httpDeleteSignTaskDto) {
        log.info("httpDeleteSignTaskDto Request:" + JSON.toJSONString(httpDeleteSignTaskDto));
        return flowTaskService.deleteSignTaskByHttpRequest(httpDeleteSignTaskDto);
    }

    @Override
    public ResponseResult<MustExpressDTO> mustExpress(TaskApproveUrlQueryVo taskApproveUrlQueryVo) {
        log.info("mustExpress Request:" + JSON.toJSONString(taskApproveUrlQueryVo));
        String mustExpress = flowTaskService.mustExpress(taskApproveUrlQueryVo.getTaskId());
        MustExpressDTO mustExpressDTO = new MustExpressDTO();
        mustExpressDTO.setMustExpress(mustExpress);
        return ResponseResult.success(mustExpressDTO);
    }

    @Override
    public ResponseResult<List<ObjectMetaDto>> queryObjectMeta(ObjectMetaQueryDto objectMetaQueryDto) {
        ProcessObjectMetaQueryDTO queryDTO = new ProcessObjectMetaQueryDTO();
        BeanUtils.copyProperties(objectMetaQueryDto, queryDTO);
        try {
            ProcessObjectMetaQueryResultDTO resultDTO = flowObjectMetaService.queryObjectMeta(queryDTO);
            return convertObjectMetaToDto(resultDTO);
        } catch (Exception ex) {
            log.error("error query object meta", ex);
            return ResponseResult.fail(
                    ErrorCode.OBJECT_META_PROCESS_QUERY_FAIL.errCode(),
                    ErrorCode.OBJECT_META_PROCESS_QUERY_FAIL.errMessage() + ": " + ex.getMessage());
        }
    }

    @Override
    public ResponseResult bindObjectIdWithTask(ObjectProcessInstanceVo opiVo) {
        if (StringUtils.isEmpty(opiVo.getObjectInstanceId())) {
            return ResponseResult.fail(404, "objectInstanceId请求参数不可为空");
        }
        if (StringUtils.isEmpty(opiVo.getProcessInstanceId())) {
            return ResponseResult.fail(404, "processInstanceId请求参数不可为空");
        }
        if (StringUtils.isEmpty(opiVo.getTaskNodeCode())) {
            return ResponseResult.fail(404, "taskNodeCode请求参数不可为空");
        }
        List<ModelFlowObjectProcessInstanceDomain> domainList = flowObjectProcessInstanceRepository.getFlowObjectProcessInstanceDomailList(null, opiVo.getProcessInstanceId(), opiVo.getTaskNodeCode());
        if (domainList != null && domainList.size() > 0) {
            for (ModelFlowObjectProcessInstanceDomain vo : domainList) {
                if (!opiVo.getObjectInstanceId().equalsIgnoreCase(vo.getObjectInstanceId())) {
                    ModelFlowObjectProcessInstance entity = new ModelFlowObjectProcessInstance();
                    BeanCopierUtils.copyProperties(vo, entity);
                    entity.setUpdateTime(new Date());
                    entity.setObjectInstanceId(opiVo.getObjectInstanceId());
                    flowObjectProcessInstanceRepository.updateByPrimaryKeySelective(entity);
                }
            }
        } else {
            ModelFlowObjectProcessInstance record = new ModelFlowObjectProcessInstance();
            record.setTaskNodeCode(opiVo.getTaskNodeCode());
            record.setObjectInstanceId(opiVo.getObjectInstanceId());
            record.setProcessInstanceId(opiVo.getProcessInstanceId());
            record.setCreateTime(new Date());
            flowObjectProcessInstanceRepository.insertSelective(record);
        }

        return ResponseResult.success();
    }

    @Override
    public ResponseResult<List<ObjectProcessInstanceVo>> getObjectProcessInstanceList(ObjectProcessInstanceVo objInstVo) {
        ResponseResult<List<ObjectProcessInstanceVo>> responseResult = ResponseResult.success();
        if (StringUtils.isNotEmpty(objInstVo.getProcessInstanceId()) || StringUtils.isNotEmpty(objInstVo.getObjectInstanceId()) || StringUtils.isNotEmpty(objInstVo.getTaskNodeCode())) {
            List<ObjectProcessInstanceVo> voList = new ArrayList<>();
            List<ModelFlowObjectProcessInstanceDomain> recordList = flowObjectProcessInstanceRepository.getFlowObjectProcessInstanceDomailList(objInstVo.getObjectInstanceId(), objInstVo.getProcessInstanceId(), objInstVo.getTaskNodeCode());
            if (recordList != null && recordList.size() > 0) {
                for (ModelFlowObjectProcessInstanceDomain vo : recordList) {
                    ObjectProcessInstanceVo entity = new ObjectProcessInstanceVo();
                    entity.setObjectInstanceId(vo.getObjectInstanceId());
                    entity.setProcessInstanceId(vo.getProcessInstanceId());
                    entity.setTaskNodeCode(vo.getTaskNodeCode());
                    voList.add(entity);
                }
            }
            responseResult.setTotalCount(voList.size());
            responseResult.setPageSize(voList.size());
            responseResult.setPageNum(1);
            responseResult.setDatas(voList);
        } else {
            return ResponseResult.fail(404, "请求参数不可都为空");
        }

        return responseResult;
    }

    private ResponseResult<List<ObjectMetaDto>> convertObjectMetaToDto(ProcessObjectMetaQueryResultDTO resultDTO) {
        ResponseResult<List<ObjectMetaDto>> responseResult = ResponseResult.success();
        responseResult.setTotalCount(resultDTO.getTotal().intValue());
        responseResult.setPageNum(resultDTO.getPageNum());
        responseResult.setPageSize(resultDTO.getPageSize());

        List<ObjectMetaDto> metaDtos = new ArrayList<>();
        responseResult.setDatas(metaDtos);

        if (CollectionUtils.isEmpty(resultDTO.getObjectMetaDTOList())) {
            return responseResult;
        }

        for (ProcessObjectMetaDTO processObjectMetaDTO : resultDTO.getObjectMetaDTOList()) {
            ObjectMetaDto out = new ObjectMetaDto();
            //deep copy，所以属性不用单独再次拷贝
            BeanUtils.copyProperties(processObjectMetaDTO, out);
            metaDtos.add(out);
        }

        return responseResult;
    }

    @Override
    public ResponseResult<TaskVariableSetResponseDto> setTaskVariable(TaskVariableSetRequestDto requestDto) {
        try {
            TaskVariableSetRequestVo requestVo = new TaskVariableSetRequestVo();
            BeanUtils.copyProperties(requestDto, requestVo);
            TaskVariableSetResponseVo responseVo = taskVariableRepository.setTaskVariable(requestVo);
            TaskVariableSetResponseDto rspDto = new TaskVariableSetResponseDto();
            BeanUtils.copyProperties(responseVo, rspDto);
            return ResponseResult.success(rspDto);
        } catch (Exception ex) {
            log.error("error set task variable: " + ex.getMessage(), ex);
            return ResponseResult.fail(
                    ErrorCode.TASK_VARIABLE_SET_ERROR.errCode(),
                    ErrorCode.TASK_VARIABLE_SET_ERROR.errMessage() + ":" + ex.getMessage());
        }
    }

    @Override
    public ResponseResult<TaskVariablesSetResponseDto> setTaskVariables(TaskVariablesSetRequestDto request) {
        try {
            TaskVariablesSetResponseDto responseDto = new TaskVariablesSetResponseDto();
            responseDto.setResponseDtos(new ArrayList<>());
            for(TaskVariableSetRequestDto requestDto:request.getVariables()) {
                TaskVariableSetRequestVo requestVo = new TaskVariableSetRequestVo();
                BeanUtils.copyProperties(requestDto, requestVo);
                if(StringUtils.isNotEmpty(request.getProcessInstanceId())) {
                    requestVo.setProcessInstanceId(request.getProcessInstanceId());
                }
                if(StringUtils.isNotEmpty(request.getWorkItemId())) {
                    requestVo.setWorkItemId(request.getWorkItemId());
                }
                TaskVariableSetResponseVo responseVo = taskVariableRepository.setTaskVariable(requestVo);
                TaskVariableSetResponseDto rspDto = new TaskVariableSetResponseDto();
                BeanUtils.copyProperties(responseVo, rspDto);
                responseDto.getResponseDtos().add(rspDto);
            }
            return ResponseResult.success(responseDto);
        } catch (Exception ex) {
            log.error("error set task variables: " + ex.getMessage(), ex);
            return ResponseResult.fail(
                    ErrorCode.TASK_VARIABLE_SET_ERROR.errCode(),
                    ErrorCode.TASK_VARIABLE_SET_ERROR.errMessage() + ":" + ex.getMessage());
        }
    }

    @Override
    public ResponseResult setAssigneeForNode(SetNodeCandidateRequestDto setNodeCandidateRequestDto) {
        log.info("setAssigneeForNode Request:" + JSON.toJSONString(setNodeCandidateRequestDto));
        FlowTaskTraceVo flowTaskTraceVo = null;
        if (setNodeCandidateRequestDto.getCheckUser()) {
            flowTaskTraceVo = flowTaskService.getFlowTaskByTaskIdOrUserCode(setNodeCandidateRequestDto.getTaskId(), setNodeCandidateRequestDto.getUserCode());
        } else {
            flowTaskTraceVo = flowTaskService.getFlowTaskByTaskIdOrUserCode(setNodeCandidateRequestDto.getTaskId(), null);
        }

        if (Objects.isNull(flowTaskTraceVo)) {
            return ResponseResult.fail(ErrorCode.NOT_TASK_CANDIDATE_OR_TASK_NOT_EXIST.errCode(), ErrorCode.NOT_TASK_CANDIDATE_OR_TASK_NOT_EXIST.errMessage());
        }

        List<NodeCandidateDto> nodeCandidateDtoList = setNodeCandidateRequestDto.getNodeCandidateList();

        if (CollectionUtils.isNotEmpty(nodeCandidateDtoList)) {

            String nodeCode = flowTaskTraceVo.getActivityId();
            NextNodeCandidateTaskDTO nextNodeCandidateTaskDTO = new NextNodeCandidateTaskDTO();
            nextNodeCandidateTaskDTO.setTaskId(setNodeCandidateRequestDto.getTaskId());
            List<NodeCandidateTaskDTO> nodeCandidateTaskDTOList = new ArrayList<>();

            for (NodeCandidateDto nodeCandidateDto : nodeCandidateDtoList) {
                NodeCandidateTaskDTO nodeCandidateTaskDTO = new NodeCandidateTaskDTO();
                nodeCandidateTaskDTO.setNodeCode(nodeCandidateDto.getNodeCode());
                nodeCandidateTaskDTO.setDataType(nodeCandidateDto.getCandidateType());
                nodeCandidateTaskDTO.setCode(nodeCandidateDto.getCandidateValue());
                nodeCandidateTaskDTO.setName(nodeCandidateDto.getCandidateName());
                nodeCandidateTaskDTO.setFromNodeCode(nodeCode);
                nodeCandidateTaskDTOList.add(nodeCandidateTaskDTO);
            }
            nextNodeCandidateTaskDTO.setNodeCandidateTaskDTOList(nodeCandidateTaskDTOList);
            try {
                nodeCandidateService.setAssigneeForNode(nextNodeCandidateTaskDTO);
            } catch (Exception e) {
                log.error("setAssigneeForNode error:", e);
                return ResponseResult.fail(ErrorCode.SET_PARTICIPANTS_FAILED.errCode(), e.getMessage());
            }
        } else {
            return ResponseResult.fail(ErrorCode.CANDIDATE_NOT_EXIST.errCode(), "节点处理人数据为空，请核实后再次尝试");
        }

        if (StringUtils.isNotBlank(setNodeCandidateRequestDto.getComment())) {
            nodeCandidateService.addComment(setNodeCandidateRequestDto.getTaskId(), setNodeCandidateRequestDto.getUserCode(), flowTaskTraceVo.getProcessInstanceId(), CommentTypeEnum.ZDSPR.getName(), setNodeCandidateRequestDto.getComment());
        }

        return ResponseResult.success("设置处理人成功");
    }

    @Override
    public ResponseResult getChildCandidate(HttpCandidateDto httpCandidateDto) {
        log.info("getCandidateInfoList Request:" + JSON.toJSONString(httpCandidateDto));
        FlowTaskCandidateDataTypeVo dataTypeVo = null;
        try {
            dataTypeVo = flowTaskService.getChildCandidate(httpCandidateDto.getType(), httpCandidateDto.getCode(), httpCandidateDto.getProcessInstanceId(), httpCandidateDto.getUserCode());
        } catch (Exception ex) {
            log.error("getCandidateInfoList error: " + ex.getMessage(), ex);
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), ex.getMessage());
        }
        log.info("getCandidateInfoList Response:" + JSON.toJSONString(dataTypeVo));
        return ResponseResult.success(dataTypeVo);
    }

    /**
     * 根据角色名称分页查询角色列表
     *
     * @param vo
     * @return
     */
    @Override
    public ResponseResult getUserRolePageList(UserRolePageRequestDto vo) {
        return userRoleService.getUserRolePageList(vo.getRoleName(), vo.getPageNo(), vo.getPageSize());
    }

    /**
     * 根据用户组名称查询用户组列表
     *
     * @param vo
     * @return
     */
    @Override
    public ResponseResult getUserGroupPageList(UserGroupPageRequestDto vo) {
        return userGroupService.getUserGroupPageList(vo.getGroupName(), vo.getPageNo(), vo.getPageSize());
    }

    @Override
    public ResponseResult getVarVal(VarValRequestDto varValRequestDto) {
        log.info("getVarVal Request:" + JSON.toJSONString(varValRequestDto));
        Object value = null;
        String taskId = varValRequestDto.getTaskId();
        String varKey = varValRequestDto.getVarKey();
        if (StringUtils.isNotEmpty(taskId)) {
            value = flowTaskVariableService.getTaskVariableByTaskIdAndKey(taskId, varKey);
        } else {
            value = flowTaskVariableService.getVariableByProcessIdAndKey(varValRequestDto.getProcessInstanceId(), varKey);
        }
        log.info("getVarVal Response:" + JSON.toJSONString(value));
        return ResponseResult.success(value);

    }

    /**
     * 根据岗位名称获取岗位数据列表
     *
     * @param vo
     * @return
     */
    @Override
    public ResponseResult getUserPositionPageList(UserPositionPageRequestDto vo) {
        return userPositionService.getUserPositionPageList(vo.getPositionName(), vo.getPageNo(), vo.getPageSize());
    }

    /**
     * 获取上次设置的候选人
     *
     * @param taskId
     * @param nodeCode
     * @return
     */
    @Override
    public ResponseResult getLastCandidate(String taskId, String nodeCode) {
        log.info("getLastCandidate Request:taskId=" + taskId + ";nodeCode=" + nodeCode);
        List<ModelNextNodeCandidateSettings> lastSetttingsCandidate = null;
        try {
            lastSetttingsCandidate = flowTaskService.getLastCandidate(taskId, nodeCode);
        } catch (Exception e) {
            logger.error("getLastCandidate error", e);
            return ResponseResult.fail(ErrorCode.GET_LAST_SET_CANDIDATE_FAIL.errCode(), e.getMessage());
        }
        log.info("getLastCandidate Response: " + JSON.toJSONString(lastSetttingsCandidate));

        return ResponseResult.success(lastSetttingsCandidate);
    }

    /**
     * 获取所有上次设置的候选人
     *
     * @param processInstanceId
     * @return
     */
    @Override
    public ResponseResult getAllLastCandidate(String processInstanceId) {
        log.info("getAllLastCandidate Request:processInstanceId=" + processInstanceId);
        List<NodeCandidateUsersSetting> candidateUsersSettings = null;
        try {
            candidateUsersSettings = flowTaskService.getAllLastCandidate(processInstanceId);
        } catch (Exception e) {
            logger.error("getAllLastCandidate error", e);
            return ResponseResult.fail(ErrorCode.GET_LAST_SET_CANDIDATE_FAIL.errCode(), e.getMessage());
        }
        log.info("getAllLastCandidate Response: " + JSON.toJSONString(candidateUsersSettings));
        return ResponseResult.success(candidateUsersSettings);
    }

    /**
     * 获取指定节点最新设置的候选人或者最近审批人信息
     *
     * @param processInstanceId
     * @param nodeCode
     * @return
     */
    @Override
    public ResponseResult getLastCandidateOrOperator(String processInstanceId, String nodeCode) {
        log.info("getLastCandidateOrOperator Request:processInstanceId={},nodeCode={}", processInstanceId, nodeCode);
        ResponseResult responseResult = null;
        try {
            responseResult = flowTaskService.getLastCandidateOrOperator(processInstanceId, nodeCode);
        } catch (Exception e) {
            logger.error("getLastCandidateOrOperator error", e);
            return ResponseResult.fail(ErrorCode.GET_LAST_CANDIDATE_OPERATOR_FAIL.errCode(), e.getMessage());
        }
        log.info("getLastCandidateOrOperator Response: " + JSON.toJSONString(responseResult));
        return responseResult;
    }

    /**
     * 操作流程实例(支持暂停(挂起)或激活(解挂)操作)
     *
     * @param httpProcessHandleDto
     * @return
     */
    @Override
    public ResponseResult handleProcessInstanceByAction(HttpProcessHandleDto httpProcessHandleDto) {
        log.info("handleProcessInstanceByAction Request:" + JSON.toJSONString(httpProcessHandleDto));
        // 根据action触发相应的操作
        try {
            flowProcessService.handleProcessInstanceByAction(httpProcessHandleDto);
        } catch (BusiException bex) {
            log.error("处理失败,流程实例ID:{}:", httpProcessHandleDto.getProcessInstanceId(), bex);
            return ResponseResult.fail(ErrorCode.PROCESS_HANDLE_FAIL.errCode(), bex.getMessage());
        } catch (Exception ex) {
            log.error("处理失败,流程实例ID:{}:", httpProcessHandleDto.getProcessInstanceId(), ex);
            // 暂停(挂起)
            if (Objects.equals(httpProcessHandleDto.getAction(), ProcessInstanceActionEnum.PAUSE.getCode())) {
                return ResponseResult.fail(ErrorCode.PROCESS_SUSPEND_FAIL.errCode(), ex.getMessage());
            }
            // 激活(解挂)
            if (Objects.equals(httpProcessHandleDto.getAction(), ProcessInstanceActionEnum.UNPAUSE.getCode())) {
                return ResponseResult.fail(ErrorCode.PROCESS_ACTIVATE_FAIL.errCode(), ex.getMessage());
            }
        }
        return ResponseResult.success("处理成功");
    }

    /**
     * 操作任务实例(支持暂停(挂起)或激活(解挂)操作)
     *
     * @param httpProcessHandleDto
     * @return
     */
    @Override
    public ResponseResult handleTaskByAction(HttpProcessHandleDto httpProcessHandleDto) {
        log.info("handleTaskByAction Request:" + JSON.toJSONString(httpProcessHandleDto));
        // 根据action触发相应的操作
        try {
            flowProcessService.handleTaskByAction(httpProcessHandleDto);
        } catch (BusiException bex) {
            log.error("处理失败,任务实例ID:{}:", httpProcessHandleDto.getTaskId(), bex);
            return ResponseResult.fail(ErrorCode.TASK_HANDLE_FAIL.errCode(), bex.getMessage());
        } catch (Exception ex) {
            log.error("处理失败,任务实例ID:{}:", httpProcessHandleDto.getTaskId(), ex);
            // 暂停(挂起)
            if (Objects.equals(httpProcessHandleDto.getAction(), ProcessInstanceActionEnum.PAUSE.getCode())) {
                return ResponseResult.fail(ErrorCode.TASK_SUSPEND_FAIL.errCode(), ex.getMessage());
            }
            // 激活(解挂)
            if (Objects.equals(httpProcessHandleDto.getAction(), ProcessInstanceActionEnum.UNPAUSE.getCode())) {
                return ResponseResult.fail(ErrorCode.TASK_ACTIVATE_FAIL.errCode(), ex.getMessage());
            }
        }
        return ResponseResult.success("处理成功");
    }

    @Override
    public ResponseResult getManualSelectNextNode(HttpBaseTaskDto httpBaseTaskDto) {
        log.info("getManualSelectNextNode Request:" + JSONObject.toJSONString(httpBaseTaskDto));
        BaseTaskVo taseTask = new BaseTaskVo();
        taseTask.setTaskId(httpBaseTaskDto.getTaskId());
        List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList = null;
        try {
            nextNodeWithGatewayParamKeyList = sequentNodeCandidateConfigService.getNextNodeByGatewayKey(taseTask);
        } catch (Exception e) {
            log.error("getNextNodeByGatewayKey error", e);
            return ResponseResult.fail(BAD_REQUEST.errCode(), e.getMessage());
        }
        log.info("getManualSelectNextNode Response:" + JSONObject.toJSONString(nextNodeWithGatewayParamKeyList));
        return ResponseResult.success(nextNodeWithGatewayParamKeyList);
    }

    @Override
    public ResponseResult supplySignTask(HttpSupplySignTaskVo httpSupplySignTaskVo) {
        CommonOperateLogHolder.setFromSdk(true);
        ResponseResult responseResult;
        try {
            log.info("supplySignTask Request:" + JSONObject.toJSONString(httpSupplySignTaskVo));
            SupplySignTaskVo supplySignTaskVo = new SupplySignTaskVo();
            BeanCopierUtils.copyProperties(httpSupplySignTaskVo, supplySignTaskVo);
            if (CollectionUtils.isNotEmpty(httpSupplySignTaskVo.getReissueHandlers())) {
                List<SupplyPersonVo> supplyPersonVoList = new ArrayList<>();
                httpSupplySignTaskVo.getReissueHandlers().stream().forEach(str -> {
                    SupplyPersonVo supplyPersonVo = new SupplyPersonVo();
                    supplyPersonVo.setCode(str);
                    supplyPersonVo.setType("STA");
                    supplyPersonVoList.add(supplyPersonVo);
                });
                supplySignTaskVo.setSupplyPersonList(supplyPersonVoList);
            }
            responseResult = flowSupplyNodeService.supplySignTask(supplySignTaskVo);
        } finally {
            CommonOperateLogHolder.removeAll();
        }
        return responseResult;
    }

    @Override
    public ResponseResult setCandidateUsersForNode(SetNodeCandidateRequestDto setNodeCandidateRequestDto) {
        log.info("setCandidateUsersForNode Request:" + JSON.toJSONString(setNodeCandidateRequestDto));
        if (Objects.isNull(setNodeCandidateRequestDto.getProcessInstanceId())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), PARAM_NOT_EXIST.errMessage());
        }
        List<NodeCandidateDto> nodeCandidateDtoList = setNodeCandidateRequestDto.getNodeCandidateList();
        if (CollectionUtils.isNotEmpty(nodeCandidateDtoList)) {
            String fromNodeCode = setNodeCandidateRequestDto.getFromNodeCode();
            NextNodeCandidateTaskDTO nextNodeCandidateTaskDTO = new NextNodeCandidateTaskDTO();
            nextNodeCandidateTaskDTO.setProcessInstanceId(setNodeCandidateRequestDto.getProcessInstanceId());
            nextNodeCandidateTaskDTO.setTaskId(setNodeCandidateRequestDto.getTaskId());
            List<NodeCandidateTaskDTO> nodeCandidateTaskDTOList = new ArrayList<>();
            for (NodeCandidateDto nodeCandidateDto : nodeCandidateDtoList) {
                NodeCandidateTaskDTO nodeCandidateTaskDTO = new NodeCandidateTaskDTO();
                nodeCandidateTaskDTO.setNodeCode(nodeCandidateDto.getNodeCode());
                nodeCandidateTaskDTO.setDataType(nodeCandidateDto.getCandidateType());
                nodeCandidateTaskDTO.setCode(nodeCandidateDto.getCandidateValue());
                nodeCandidateTaskDTO.setName(nodeCandidateDto.getCandidateName());
                nodeCandidateTaskDTO.setFromNodeCode(fromNodeCode);
                nodeCandidateTaskDTOList.add(nodeCandidateTaskDTO);
            }
            nextNodeCandidateTaskDTO.setNodeCandidateTaskDTOList(nodeCandidateTaskDTOList);
            try {
                nodeCandidateService.setCandidateUsersForNode(nextNodeCandidateTaskDTO);
            } catch (Exception e) {
                log.error("setAssigneeForNode error:", e);
                return ResponseResult.fail(ErrorCode.SET_PARTICIPANTS_FAILED.errCode(), e.getMessage());
            }
        } else {
            return ResponseResult.fail(ErrorCode.CANDIDATE_NOT_EXIST.errCode(), "节点处理人数据为空，请核实后再次尝试");
        }
        return ResponseResult.success("设置处理人成功");
    }


    @Override
    public ResponseResult cleanNodeCandidateUsers(CleanNodeCandidateRequestDto cleanNodeCandidateRequestDto) {
        log.info("cleanNodeCandidateUsers Request:" + JSON.toJSONString(cleanNodeCandidateRequestDto));
        if (Objects.isNull(cleanNodeCandidateRequestDto.getProcessInstanceId()) || Objects.isNull(cleanNodeCandidateRequestDto.getNodeCodes())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), PARAM_NOT_EXIST.errMessage());
        }
        try {
            nodeCandidateService.cleanNodeCandidateUsers(cleanNodeCandidateRequestDto.getProcessInstanceId(), cleanNodeCandidateRequestDto.getNodeCodes());
        } catch (Exception e) {
            log.error("cleanNodeCandidateUsers error:", e);
            return ResponseResult.fail(ErrorCode.CLEAN_PARTICIPANTS_FAILED.errCode(), e.getMessage());
        }
        return ResponseResult.success("清除处理人成功");
    }

    @Override
    public ResponseResult<TaskDTO> getCurrentOrDoneTaskIdByProcessInstanceId(String processInstanceId) {
        ResponseResult result;
        try {
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
            if (taskList != null && taskList.size() > 0) {
                log.info("根据实例ID[" + processInstanceId + "]查询任务记录结果[" + taskList + "]");
                TaskDTO taskDTO = new TaskDTO();
                taskDTO.setTaskId(taskList.get(0).getId());
                result = ResponseResult.success(taskDTO);
            } else {
                // 查询历史
                // 根据流程实例ID获取整个流程实例最后一个任务节点
                List<HistoricTaskInstance> historyTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
                if (CollectionUtils.isNotEmpty(historyTasks)) {
                    TaskDTO taskDTO = new TaskDTO();
                    taskDTO.setTaskId(historyTasks.get(0).getId());
                    result = ResponseResult.success(taskDTO);
                } else {
                    result = ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), "根据实例ID查询任务ID失败!");
                }
            }
        } catch (Exception e) {
            result = ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), "根据实例ID查询任务ID失败.");
        }
        log.info("getCurrentOrDoneTaskIdByProcessInstanceId Result:" + JSON.toJSONString(result));
        return result;
    }

    /**
     * 批量查询流程节点审批记录
     *
     * @param httpFlowRecordsQueryDto
     * @return
     */
    @Override
    public ResponseResult batchQueryFlowRecords(HttpFlowRecordsQueryDto httpFlowRecordsQueryDto) {
        log.info("batchQueryFlowRecords Req:" + JSON.toJSONString(httpFlowRecordsQueryDto));
        if (StrUtil.isBlank(httpFlowRecordsQueryDto.getNodeCode())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "节点编码nodeCode不能为空");
        }
        if (CollectionUtils.isEmpty(httpFlowRecordsQueryDto.getProcessInstanceIds())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "流程实例Id集合processInstanceIds不能为空");
        }
        try {
            SdkCallTag.setTag(true);
            List<HttpFlowRecordsQueryVo> batchQueryFlowRecords = flowMonitorRepository.batchQueryFlowRecords(httpFlowRecordsQueryDto);
            ResponseResult result = ResponseResult.success(batchQueryFlowRecords);
            result.setTotalCount(batchQueryFlowRecords.size());
            return result;
        } catch (Exception e) {
            log.error("批量查询流程节点审批记录失败", e);
            return ResponseResult.success(new ArrayList<>());
        } finally {
            SdkCallTag.remove();
        }
    }

    /**
     * 根据多种条件查询获取任务节点列表
     *
     * @return
     */
    @Override
    public ResponseResult getTaskCodeList(HttpGetTaskDto httpGetTaskDto) {
        if (StrUtil.isBlank(httpGetTaskDto.getModelKey())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "流程模型编码modelKey不能为空");
        }
        if (StrUtil.isBlank(httpGetTaskDto.getStartTime())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "查询开始时间startTime不能为空");
        }
        if (StrUtil.isBlank(httpGetTaskDto.getEndTime())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "查询结束时间EndTime不能为空");
        }
        try {
            log.info("getTaskCodeList");
            SdkCallTag.setTag(true);
            ResponseResult result = ResponseResult.success(flowMonitorRepository.getTaskCodeList(httpGetTaskDto));
            return result;
        } catch (Exception e) {
            log.error("根据多种条件查询获取任务节点列表失败", e);
            return ResponseResult.success(new ArrayList<>());
        } finally {
            SdkCallTag.remove();
        }
    }

    /**
     * 更新待办中的【计划完成时间】
     *
     * @param httpUpdateCompTimeDto 工作项id等信息
     * @return 处理结果
     */
    @Override
    public ResponseResult updateTaskCompTime(HttpUpdateCompTimeDto httpUpdateCompTimeDto) {
        if (StrUtil.isBlank(httpUpdateCompTimeDto.getTaskId())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "任务实例编码taskId不能为空");
        }
        if (StrUtil.isBlank(httpUpdateCompTimeDto.getNewCompTime())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "最新计划完成时间newCompTime不能为空");
        }
        log.info("updateTaskCompTime Request:httpUpdateCompTimeDto={}", JSONObject.toJSONString(httpUpdateCompTimeDto));
        ResponseResult responseResult = null;
        try {
            responseResult = flowTaskService.updateTaskCompTime(httpUpdateCompTimeDto);
        } catch (Exception e) {
            logger.error("updateTaskCompTime error", e);
            return ResponseResult.fail(ErrorCode.GET_LAST_CANDIDATE_OPERATOR_FAIL.errCode(), e.getMessage());
        }
        log.info("updateTaskCompTime Response: " + JSON.toJSONString(responseResult));
        return responseResult;
    }

    /**
     * 查询指定当前在指定节点的流程集合
     *
     * @param httpGetTaskDto
     * @return 流转记录
     */
    @Override
    public ResponseResult getRunningProcessList(HttpGetTaskDto httpGetTaskDto) {
        if (StrUtil.isBlank(httpGetTaskDto.getFlowCode())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "流程模型编码flowCode不能为空");
        }
        if (StrUtil.isBlank(httpGetTaskDto.getTaskCode())) {
            return ResponseResult.fail(PARAM_NOT_EXIST.errCode(), "查询开始时间taskCode不能为空");
        }
        try {
            log.info("getRunningProcessList req:{}", JSONObject.toJSONString(httpGetTaskDto));
            SdkCallTag.setTag(true);
            List<FlowNodeRecordsDTO> flowNodeRecordsDTOS = flowMonitorRepository.getRunningProcessList(httpGetTaskDto);
            ResponseResult result = ResponseResult.success(flowNodeRecordsDTOS);
            result.setTotalCount(flowNodeRecordsDTOS.size());
            return result;
        } catch (Exception e) {
            log.error("查询指定当前在指定节点的流程集合", e);
            return ResponseResult.fail(ACTION_NOT_EXIST.errCode(), "查询指定当前在指定节点的流程集合异常：" + e.getMessage());
        } finally {
            SdkCallTag.remove();
        }
    }

    @Override
    public ResponseResult getCurrentTaskInfoByProcessInstanceId(String processInstanceId) {
        log.info("getCurrentTaskInfoByProcessInstanceId Req: processInstanceId=" + processInstanceId);
        ResponseResult result = flowTaskService.getCurrentTaskInfo(processInstanceId);
        log.info("getCurrentTaskInfoByProcessInstanceId Res:" + JSON.toJSONString(result));
        return result;
    }


    /**
     * 在流程实例中动态新增节点
     *
     * @param httpDynamicInjectTaskDto
     * @return
     */
    @Override
    public ResponseResult dynamicInjectTask(HttpDynamicInjectTaskDto httpDynamicInjectTaskDto) {
        try {
            log.info("dynamicInjectTask Request:" + JSON.toJSONString(httpDynamicInjectTaskDto));
            return flowProcessService.dynamicInjectTask(httpDynamicInjectTaskDto);
        } catch (Exception e) {
            log.error("dynamicInjectTask error:", e);
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "dynamicInjectTask error：" + e.getMessage());
        }
    }

    /**
     * 将流程实例迁移至流程最新版本
     *
     * @param httpMigrateProcessModelDto
     * @return
     */
    @Override
    public ResponseResult migrateToNewVersion(HttpMigrateProcessModelDto httpMigrateProcessModelDto) {
        try {
            log.info("migrateToNewVersion Request:" + JSON.toJSONString(httpMigrateProcessModelDto));
            return flowProcessService.migrateToNewVersion(httpMigrateProcessModelDto);
        } catch (Exception e) {
            log.error("migrateToNewVersion error:", e);
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "migrateToNewVersion error：" + e.getMessage());
        }

    }

    /**
     * 根据modelKey获取模型配置的事件
     *
     * @param modelKey
     * @return
     */
    @Override
    public ResponseResult getConfigEvents(@RequestParam("modelKey") String modelKey) {
        if (StringUtils.isBlank(modelKey)) {
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "modelKey不能为空");
        }
        String modelId = modelRepository.transferModelKeyToId(modelKey);
        if (StringUtils.isBlank(modelId)) {
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "modelKey转换为modelId失败,请核对modelKey");
        }
        List<DeployedEventConfigDomain> result = flowEventConfigRepository.getEventConfigListByModelId(modelId);
        return ResponseResult.success(result);
    }

    /**
     * 根据模型key查询待办任务信息
     *
     * @param httpFlowQueryInfoDto
     * @return
     */
    @Override
    public ResponseResult getTodoTaskByModelKey(HttpFlowQueryInfoDto httpFlowQueryInfoDto) {
        PageInfo<HttpFlowQueryInfoDto> pageInfos = new PageInfo<>(flowExecutionQueryService.todoTasksByModelKey(httpFlowQueryInfoDto));
        return ResponseResult.success(pageInfos.getList()).setTotalCount((int) pageInfos.getTotal())
                .setPageNum(pageInfos.getPageNum()).setPageSize(pageInfos.getPageSize());
    }


    /**
     * 根据条件查询流程实例列表
     */
    @Override
    public ResponseResult list(HttpProcessInstanceQueryDto httpProcessInstanceQueryDto) {
        try {

            ProcessInstanceQueryVo processInstanceQueryVo = new ProcessInstanceQueryVo();
            BeanUtils.copyProperties(httpProcessInstanceQueryDto, processInstanceQueryVo);
            processInstanceQueryVo.setNeedCheckAuth(false);
            PageInfo<FlowProcessInstanceTraceForMonitorVo> pageInfos = new PageInfo<>(flowProcessInstanceTraceRepository.list(processInstanceQueryVo));
            return ResponseResult.success(pageInfos.getList()).setTotalCount((int) pageInfos.getTotal())
                    .setPageNum(pageInfos.getPageNum()).setPageSize(pageInfos.getPageSize());
        } catch (Exception ex) {
            log.error("查询流程实例列表时失败,失败原因：{}", ex.getMessage(), ex);
            return ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), ex.getMessage());
        }

    }

    /**
     * 根据流程编码获取当前运行的流程实例的modelId
     *
     * @param modelKey
     * @return
     */
    @Override
    public ResponseResult getModelInfoByModelKey(String modelKey) {
        ResponseResult result = modelRepository.getModelByModelKey(modelKey);
        return result;
    }

    @Override
    public ResponseResult getNextNodes(HttpBaseTaskDto httpBaseTaskDto) {
        log.info("getNextNodes Request:" + JSONObject.toJSONString(httpBaseTaskDto));
        BaseTaskVo taseTask = new BaseTaskVo();
        taseTask.setTaskId(httpBaseTaskDto.getTaskId());
        List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList = null;
        try {
            nextNodeWithGatewayParamKeyList = sequentNodeCandidateConfigService.getNextNodesByNodeId(taseTask);
        } catch (Exception e) {
            log.error("getNextNodes error", e);
            return ResponseResult.fail(BAD_REQUEST.errCode(), e.getMessage());
        }
        log.info("getNextNodes Response:" + JSONObject.toJSONString(nextNodeWithGatewayParamKeyList));
        return ResponseResult.success(nextNodeWithGatewayParamKeyList);
    }

    /**
     * 批量同步待办任务至待办组件
     *
     * @param httpTaskManagerBatchDto
     * @return
     */
    @Override
    public ResponseResult batchInsertToTasksManager(HttpTaskManagerBatchDto httpTaskManagerBatchDto) {
        log.info("batchInsertToTasksManager Request:" + JSONObject.toJSONString(httpTaskManagerBatchDto));
        if (ObjectUtils.isEmpty(httpTaskManagerBatchDto)) {
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "tasksManagerDTOS不能为空");
        }
        if ((CollectionUtils.isEmpty(httpTaskManagerBatchDto.getTasksManagerDTOS())) && CollectionUtils.isEmpty(httpTaskManagerBatchDto.getTaskIds())) {
            return ResponseResult.fail(ErrorCode.BAD_REQUEST.errCode(), "httpTaskManagerBatchDto 与taskIds 不能同时为空");
        }
        ResponseResult<String> responseResult = ResponseResult.success();
        try {
            responseResult = flowTaskService.batchInsertToTasksManager(httpTaskManagerBatchDto);
        } catch (Exception e) {
            log.error("batchInsertToTasksManager error", e);
            return ResponseResult.fail(BAD_REQUEST.errCode(), e.getMessage());
        }
        log.info("batchInsertToTasksManager Response:" + JSONObject.toJSONString(responseResult));
        return responseResult;
    }

    /**
     * 根据流程id判断流程是否已经结束
     */
    @Override
    public ResponseResult getFlowStateByFlowId(String flowId) {
        ResponseResult<String> responseResult = ResponseResult.success();
        String result = flowProcessInstanceTraceRepository.queryFlowStateByFlowId(flowId);
        if ("NORMAL".equals(result)){
            responseResult = ResponseResult.fail(200,result);
        }
        return responseResult;
    }
    private static List<String> nodeList;
    private static Map<String,String> nodeMap;
    static {
        nodeList = new ArrayList<>();// 利用list有序原理，后续修改节点审批人（运维工具）功能需要
        nodeList.add("FEEDBACK_02");// 编制人3
        nodeList.add("FEEDBACK_03");// 编制人2
        nodeList.add("FEEDBACK_04");// 编制人1
        nodeList.add("FEEDBACK_05");// 评价人
        nodeMap = new HashMap<>();
        nodeMap.put("FEEDBACK_02","ASSIGN3");// 编制人3
        nodeMap.put("FEEDBACK_03","ASSIGN2");// 编制人2
        nodeMap.put("FEEDBACK_04","ASSIGN1");// 编制人1
        nodeMap.put("FEEDBACK_05","EVALPERS");// 评价人
    }

    /**
     * 反馈流程修改节点审批人（运维工具）
     * @param modifyApproverVO
     * @return
     */
    @Override
    public ResponseResult updateNodeApprover(HttpModifyApproverVO modifyApproverVO) {
        log.info("反馈流程修改节点审批人（运维工具），BEGIN，modifyApproverVO：{}",modifyApproverVO);
        String flag = processService.queryCurrentNodeByFlowId(modifyApproverVO);
        log.info("反馈流程修改节点审批人（运维工具），END，modifyApproverVO：{}",modifyApproverVO);
        return ResponseResult.success(flag);
    }
}